package net.sshiffon.jctermish;

import com.jcraft.jcterm.Connection;
import com.jcraft.jcterm.Sftp;
import com.jcraft.jcterm.Splash;
import com.jcraft.jcterm.Term;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.HostKey;
import com.jcraft.jsch.HostKeyRepository;
import com.jcraft.jsch.Proxy;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.lang.Thread;
import net.sshiffon.TerminalConnector;
import org.apache.log4j.Logger;

/**
 *
 * @author Jasmini
 */
public class JCTermishConnector implements TerminalConnector {
  private static Logger logger = Logger.getLogger(JCTermishConnector.class);
  private static final int SHELL=0;
  private static final int SFTP=1;

  private int mode=SHELL;

  public static final String KNOWN_HOSTS="known_hosts";

  private String xhost="127.0.0.1";
  private int xport=0;
  private boolean xforwarding=false;
  private String user="amir";
  private String host="127.0.0.1";
  private int port=22;

  private SshSessionManager jschsession=null;
  
  private Proxy proxy=null;

  private int compression=0;

  @SuppressWarnings("unused")
private Splash splash=null;

  public SshiffonTerm term=new SshiffonTerm();

  private Connection connection=null;



private Thread thread=null;

{
    term.setEnabled(true);
    term.setVisible(true);

    //term.setBackground(Color.white);
    //term.setForeground(Color.black);

}

public void setCredentials(String user, String host, int port )
{
    this.user = user;
    this.host = host;
    this.port = port;
}

public String getUser()
{
  return user;
}
public String getHost()
{
    return host;
}
public int getPort()
{
    return port;
}

  public void kick(){
    this.thread=new Thread(this);
    this.thread.start();
  }

  public void saveKeys()
  {
                HostKeyRepository hkr = jschsession.getJSch().getHostKeyRepository();

          HostKey[] hks= hkr.getHostKey();
          if(hks!=null)
          {
            FileWriter f = null;
            try {
                logger.debug("host keys in " + hkr.getKnownHostsRepositoryID());
                f = new FileWriter(KNOWN_HOSTS);
                for (HostKey hk : hks) {
                    // + " " + hk.getFingerPrint(jschsession.getJSch()) +
                    f.append(hk.getHost() + " " + hk.getType() + " " + hk.getKey() + "\n");

                    logger.debug(hk.getHost() + " " + hk.getType() + " " + hk.getKey() + " " + hk.getFingerPrint(jschsession.getJSch()));
                }
                f.close();
            } catch (IOException ex) {
                logger.error("error writing hosts file", ex);
            } catch(Exception ex) {
                logger.error("error writing hosts file", ex);
            } finally {
                try {
                    f.close();
                } catch (IOException ex) {
                    logger.error("error closing hosts file", ex);
                }
            }


          }

  }

  public void run() {
                    logger.debug("Connecting "+user+" "+host+" "+port+" "+mode);
    while(thread!=null)
    {
      try{
    
        try{
          UserInfo ui=new MyUserInfo();

          jschsession= SshSessionManager.getSession(user, null, host, port, ui, proxy, KNOWN_HOSTS);
          java.util.Properties config=new java.util.Properties();
          if(compression==0){
            config.put("compression.s2c", "none");
            config.put("compression.c2s", "none");
          }
          else{
            config.put("compression.s2c", "zlib,none");
            config.put("compression.c2s", "zlib,none");
          }
          jschsession.getSession().setConfig(config);
          jschsession.getSession().rekey();
        }
        catch(Exception e) {
            if(!e.getMessage().equals("Auth cancel"))
            {
                JOptionPane.showMessageDialog(null, e.getMessage(), "Connection Fail", JOptionPane.ERROR_MESSAGE);
            }
            e.printStackTrace();
//          return;
            break;
        }

        Channel channel=null;
        OutputStream out=null;
        InputStream in=null;

        if(mode==SHELL){
          channel=jschsession.getSession().openChannel("shell");
          if(xforwarding){
            jschsession.getSession().setX11Host(xhost);
            jschsession.getSession().setX11Port(xport+6000);
            channel.setXForwarding(true);
          }

          out=channel.getOutputStream();
          in=channel.getInputStream();

          channel.connect();

         saveKeys();


        }
        else if(mode==SFTP){

          out=new PipedOutputStream();
          in=new PipedInputStream();

          channel=jschsession.getSession().openChannel("sftp");

          channel.connect();

          (new Sftp((ChannelSftp)channel, (InputStream)(new PipedInputStream(
              (PipedOutputStream)out)), new PipedOutputStream(
              (PipedInputStream)in))).kick();
        }

        final OutputStream fout=out;
        final InputStream fin=in;
        final Channel fchannel=channel;

        //System.out.println("Creating 'connection'..");
        connection=new Connection(){
          public InputStream getInputStream(){
            return fin;
          }

          public OutputStream getOutputStream(){
            return fout;
          }

          public void requestResize(Term term){
            if(fchannel instanceof ChannelShell){
              int c=term.getColumnCount();
              int r=term.getRowCount();
              ((ChannelShell)fchannel).setPtySize(c, r, c*term.getCharWidth(),
                  r*term.getCharHeight());
            }
          }

          public void close(){
            fchannel.disconnect();
          }
        };

        //setTitle(user+"@"+host+(port!=22 ? new Integer(port).toString() : ""));
        //System.out.println("Starting terminal");

        term.requestFocus();
        term.start(connection);
        //System.out.println("Terminal started ...");
      }
      catch(Exception e){
        e.printStackTrace();

           JOptionPane.showMessageDialog(null, e.getMessage(), "Terminal Fail", JOptionPane.ERROR_MESSAGE);
      }
      break;
    }
    thread=null;
  }


    public void quit()
    {
        thread=null;
        if(connection!=null){
            connection.close();
            connection=null;
        }
        if(jschsession!=null)
        {
            if(jschsession.getSession()!=null)
            {
                jschsession.getSession().disconnect();
            }
            jschsession.dispose();
        }
    }


        public Session getSession()
        {
            return jschsession.getSession();
        }


    public class MyUserInfo implements UserInfo, UIKeyboardInteractive{
    public boolean promptYesNo(String str){
      Object[] options= {"yes", "no"};
      int foo=JOptionPane.showOptionDialog(JCTermishConnector.this.term, str,
          "Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
          null, options, options[0]);
      return foo==0;
    }

    String passwd=null;
    String passphrase=null;
    JTextField pword=new JPasswordField(20);

    public String getPassword(){
      return passwd;
    }

    public String getPassphrase(){
      return passphrase;
    }

    public boolean promptPassword(String message) {
      Object[] ob= {new JLabel("Enter Password"), pword};
      JOptionPane jop = new JOptionPane(ob,JOptionPane.QUESTION_MESSAGE,JOptionPane.OK_CANCEL_OPTION);
      JDialog dialog = jop.createDialog(message);
      dialog.addComponentListener(new ComponentAdapter() {
                public void componentShown(ComponentEvent e) {
                    SwingUtilities.invokeLater(new Runnable() {public void run() { pword.requestFocusInWindow();} });
                     pword.requestFocusInWindow();
                }
      });
      dialog.setVisible(true);
      int result= (Integer)jop.getValue();
      dialog.dispose();
      if(result==JOptionPane.OK_OPTION){
        passwd=pword.getText();
        return true;
      }
      else{
        return false;
      }
    }

    public boolean promptPassphrase(String message){
      return true;
    }

    public void showMessage(String message){
      JOptionPane.showMessageDialog(null, message);
    }

    final GridBagConstraints gbc=new GridBagConstraints(0, 0, 1, 1, 1, 1,
        GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0,
            0, 0), 0, 0);
    private Container panel;

    public String[] promptKeyboardInteractive(String destination, String name,
        String instruction, String[] prompt, boolean[] echo){
      panel=new JPanel();
      panel.setLayout(new GridBagLayout());

      gbc.weightx=1.0;
      gbc.gridwidth=GridBagConstraints.REMAINDER;
      gbc.gridx=0;
      panel.add(new JLabel(instruction), gbc);
      gbc.gridy++;

      gbc.gridwidth=GridBagConstraints.RELATIVE;

      JTextField[] texts=new JTextField[prompt.length];
      for(int i=0; i<prompt.length; i++){
        gbc.fill=GridBagConstraints.NONE;
        gbc.gridx=0;
        gbc.weightx=1;
        panel.add(new JLabel(prompt[i]), gbc);

        gbc.gridx=1;
        gbc.fill=GridBagConstraints.HORIZONTAL;
        gbc.weighty=1;
        if(echo[i]){
          texts[i]=new JTextField(20);
        }
        else{
          texts[i]=new JPasswordField(20);
        }
        panel.add(texts[i], gbc);
        gbc.gridy++;
      }

      if(JOptionPane.showConfirmDialog(JCTermishConnector.this.term, panel,
          destination+": "+name, JOptionPane.OK_CANCEL_OPTION,
          JOptionPane.QUESTION_MESSAGE)==JOptionPane.OK_OPTION){
        String[] response=new String[prompt.length];
        for(int i=0; i<prompt.length; i++){
          response[i]=texts[i].getText();
        }
        return response;
      }
      else{
        return null; // cancel
      }
    }
  }


}
